package com.tyros.common.datasource.lock;

import com.tyros.common.utils.Lock;
import com.tyros.common.utils.StringUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 数据库行锁
 *
 * @author zhangshuaiyin
 * @date 2022/2/16 18:29
 */
public class DatabaseLock extends Lock {

    private final DataSource dataSource;

    private String lockSql = "select * from `lock` where name = ? for update";

    public DatabaseLock(DataSource dataSource, String lockSql) {
        this.dataSource = dataSource;
        if (StringUtils.isNotBlank(lockSql)) {
            this.lockSql = lockSql;
        }
    }

    @Override
    public void lock(String name, Runnable execute) {
        Connection connection = null;
        Boolean autoCommit = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = dataSource.getConnection();
            autoCommit = connection.getAutoCommit();
            connection.setAutoCommit(false);
            preparedStatement = connection.prepareStatement(lockSql);
            preparedStatement.setString(1, name);
            preparedStatement.execute();
            // 执行业务逻辑
            execute.run();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (connection != null) {
                try {
                    connection.commit();
                } catch (SQLException ignored) {
                }
                try {
                    connection.setAutoCommit(Boolean.TRUE.equals(autoCommit));
                } catch (SQLException ignored) {
                }
                try {
                    connection.close();
                } catch (SQLException ignored) {
                }
            }
            if (null != preparedStatement) {
                try {
                    preparedStatement.close();
                } catch (SQLException ignored) {
                }
            }
        }
    }
}

